/*
 *   Copyright (C) @2021 Webank Group Holding Limited
 *   <p>
 *   Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License. You may obtain a copy of the License at
 *  <p>
 *  http://www.apache.org/licenses/LICENSE-2.0
 *   <p>
 *   Unless required by applicable law or agreed to in writing, software distributed under the License
 *   is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 *  or implied. See the License for the specific language governing permissions and limitations under
 *  he License.
 *
 */

package com.webank.openledger.contracts.storage;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.fisco.bcos.sdk.abi.FunctionReturnDecoder;
import org.fisco.bcos.sdk.abi.TypeReference;
import org.fisco.bcos.sdk.abi.datatypes.DynamicArray;
import org.fisco.bcos.sdk.abi.datatypes.DynamicBytes;
import org.fisco.bcos.sdk.abi.datatypes.Function;
import org.fisco.bcos.sdk.abi.datatypes.Type;
import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple3;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.contract.Contract;
import org.fisco.bcos.sdk.crypto.CryptoSuite;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.model.CryptoType;
import org.fisco.bcos.sdk.model.TransactionReceipt;
import org.fisco.bcos.sdk.model.callback.TransactionCallback;
import org.fisco.bcos.sdk.transaction.model.exception.ContractException;

@SuppressWarnings("unchecked")
public class History extends Contract {
    public static final String[] BINARY_ARRAY = {"608060405234801561001057600080fd5b506108ab806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063bf6f217a14610051578063d7ecbbcc1461007a575b600080fd5b34801561005d57600080fd5b5061007860048036036100739190810190610638565b6100b7565b005b34801561008657600080fd5b506100a1600480360361009c91908101906105f7565b6101e0565b6040516100ae9190610773565b60405180910390f35b6000806000846040518082805190602001908083835b6020831015156100f257805182526020820191506020810190506020830392506100cd565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902091508481600001908051906020019061013f929190610475565b5082816001019080519060200190610158929190610475565b50818190806001815401808255809150509060018203906000526020600020906002020160009091929091909150600082018160000190805460018160011615610100020316600290046101ad9291906104f5565b50600182018160010190805460018160011615610100020316600290046101d59291906104f5565b505050505050505050565b6060600080600080856040518082805190602001908083835b60208310151561021e57805182526020820191506020810190506020830392506101f9565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390209250828054905091506000821115156102695761046d565b600282026040519080825280602002602001820160405280156102a057816020015b606081526020019060019003908161028b5790505b509350600090505b8181101561046c5782818154811015156102be57fe5b90600052602060002090600202016000018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103635780601f1061033857610100808354040283529160200191610363565b820191906000526020600020905b81548152906001019060200180831161034657829003601f168201915b5050505050846002830281518110151561037957fe5b90602001906020020181905250828181548110151561039457fe5b90600052602060002090600202016001018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156104395780601f1061040e57610100808354040283529160200191610439565b820191906000526020600020905b81548152906001019060200180831161041c57829003601f168201915b5050505050846001600284020181518110151561045257fe5b9060200190602002018190525080806001019150506102a8565b5b505050919050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106104b657805160ff19168380011785556104e4565b828001600101855582156104e4579182015b828111156104e35782518255916020019190600101906104c8565b5b5090506104f1919061057c565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061052e578054855561056b565b8280016001018555821561056b57600052602060002091601f016020900482015b8281111561056a57825482559160010191906001019061054f565b5b509050610578919061057c565b5090565b61059e91905b8082111561059a576000816000905550600101610582565b5090565b90565b600082601f83011215156105b457600080fd5b81356105c76105c2826107c2565b610795565b915080825260208301602083018583830111156105e357600080fd5b6105ee83828461081e565b50505092915050565b60006020828403121561060957600080fd5b600082013567ffffffffffffffff81111561062357600080fd5b61062f848285016105a1565b91505092915050565b60008060006060848603121561064d57600080fd5b600084013567ffffffffffffffff81111561066757600080fd5b610673868287016105a1565b935050602084013567ffffffffffffffff81111561069057600080fd5b61069c868287016105a1565b925050604084013567ffffffffffffffff8111156106b957600080fd5b6106c5868287016105a1565b9150509250925092565b60006106da826107fb565b808452602084019350836020820285016106f3856107ee565b60005b8481101561072c57838303885261070e83835161073d565b925061071982610811565b91506020880197506001810190506106f6565b508196508694505050505092915050565b600061074882610806565b80845261075c81602086016020860161082d565b61076581610860565b602085010191505092915050565b6000602082019050818103600083015261078d81846106cf565b905092915050565b6000604051905081810181811067ffffffffffffffff821117156107b857600080fd5b8060405250919050565b600067ffffffffffffffff8211156107d957600080fd5b601f19601f8301169050602081019050919050565b6000602082019050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b82818337600083830152505050565b60005b8381101561084b578082015181840152602081019050610830565b8381111561085a576000848401525b50505050565b6000601f19601f83011690509190505600a265627a7a723058205adfecd049ee5abedb424dd2ee6850f13c0fc182178ab51b1e460d4d0e3746d46c6578706572696d656e74616cf50037"};

    public static final String BINARY = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", BINARY_ARRAY);

    public static final String[] SM_BINARY_ARRAY = {"608060405234801561001057600080fd5b506108ab806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806314062fe214610051578063f76822571461007a575b600080fd5b34801561005d57600080fd5b5061007860048036036100739190810190610638565b6100b7565b005b34801561008657600080fd5b506100a1600480360361009c91908101906105f7565b6101e0565b6040516100ae9190610773565b60405180910390f35b6000806000846040518082805190602001908083835b6020831015156100f257805182526020820191506020810190506020830392506100cd565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902091508481600001908051906020019061013f929190610475565b5082816001019080519060200190610158929190610475565b50818190806001815401808255809150509060018203906000526020600020906002020160009091929091909150600082018160000190805460018160011615610100020316600290046101ad9291906104f5565b50600182018160010190805460018160011615610100020316600290046101d59291906104f5565b505050505050505050565b6060600080600080856040518082805190602001908083835b60208310151561021e57805182526020820191506020810190506020830392506101f9565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390209250828054905091506000821115156102695761046d565b600282026040519080825280602002602001820160405280156102a057816020015b606081526020019060019003908161028b5790505b509350600090505b8181101561046c5782818154811015156102be57fe5b90600052602060002090600202016000018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103635780601f1061033857610100808354040283529160200191610363565b820191906000526020600020905b81548152906001019060200180831161034657829003601f168201915b5050505050846002830281518110151561037957fe5b90602001906020020181905250828181548110151561039457fe5b90600052602060002090600202016001018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156104395780601f1061040e57610100808354040283529160200191610439565b820191906000526020600020905b81548152906001019060200180831161041c57829003601f168201915b5050505050846001600284020181518110151561045257fe5b9060200190602002018190525080806001019150506102a8565b5b505050919050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106104b657805160ff19168380011785556104e4565b828001600101855582156104e4579182015b828111156104e35782518255916020019190600101906104c8565b5b5090506104f1919061057c565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061052e578054855561056b565b8280016001018555821561056b57600052602060002091601f016020900482015b8281111561056a57825482559160010191906001019061054f565b5b509050610578919061057c565b5090565b61059e91905b8082111561059a576000816000905550600101610582565b5090565b90565b600082601f83011215156105b457600080fd5b81356105c76105c2826107c2565b610795565b915080825260208301602083018583830111156105e357600080fd5b6105ee83828461081e565b50505092915050565b60006020828403121561060957600080fd5b600082013567ffffffffffffffff81111561062357600080fd5b61062f848285016105a1565b91505092915050565b60008060006060848603121561064d57600080fd5b600084013567ffffffffffffffff81111561066757600080fd5b610673868287016105a1565b935050602084013567ffffffffffffffff81111561069057600080fd5b61069c868287016105a1565b925050604084013567ffffffffffffffff8111156106b957600080fd5b6106c5868287016105a1565b9150509250925092565b60006106da826107fb565b808452602084019350836020820285016106f3856107ee565b60005b8481101561072c57838303885261070e83835161073d565b925061071982610811565b91506020880197506001810190506106f6565b508196508694505050505092915050565b600061074882610806565b80845261075c81602086016020860161082d565b61076581610860565b602085010191505092915050565b6000602082019050818103600083015261078d81846106cf565b905092915050565b6000604051905081810181811067ffffffffffffffff821117156107b857600080fd5b8060405250919050565b600067ffffffffffffffff8211156107d957600080fd5b601f19601f8301169050602081019050919050565b6000602082019050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b82818337600083830152505050565b60005b8381101561084b578082015181840152602081019050610830565b8381111561085a576000848401525b50505050565b6000601f19601f83011690509190505600a265627a7a723058202b231cdc63cb8ca5b95e5d2cb314851efb40e5cff33c4912aed9cc7fd50829ef6c6578706572696d656e74616cf50037"};

    public static final String SM_BINARY = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", SM_BINARY_ARRAY);

    public static final String[] ABI_ARRAY = {"[{\"constant\":false,\"inputs\":[{\"name\":\"cmd\",\"type\":\"bytes\"},{\"name\":\"key\",\"type\":\"bytes\"},{\"name\":\"value\",\"type\":\"bytes\"}],\"name\":\"addHistory\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"key\",\"type\":\"bytes\"}],\"name\":\"getHistory\",\"outputs\":[{\"name\":\"results\",\"type\":\"bytes[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]"};

    public static final String ABI = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", ABI_ARRAY);

    public static final String FUNC_ADDHISTORY = "addHistory";

    public static final String FUNC_GETHISTORY = "getHistory";

    protected History(String contractAddress, Client client, CryptoKeyPair credential) {
        super(getBinary(client.getCryptoSuite()), contractAddress, client, credential);
    }

    public static String getBinary(CryptoSuite cryptoSuite) {
        return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY);
    }

    public TransactionReceipt addHistory(byte[] cmd, byte[] key, byte[] value) {
        final Function function = new Function(
                FUNC_ADDHISTORY, 
                Arrays.<Type>asList(new DynamicBytes(cmd),
                new DynamicBytes(key),
                new DynamicBytes(value)),
                Collections.<TypeReference<?>>emptyList());
        return executeTransaction(function);
    }

    public void addHistory(byte[] cmd, byte[] key, byte[] value, TransactionCallback callback) {
        final Function function = new Function(
                FUNC_ADDHISTORY, 
                Arrays.<Type>asList(new DynamicBytes(cmd),
                new DynamicBytes(key),
                new DynamicBytes(value)),
                Collections.<TypeReference<?>>emptyList());
        asyncExecuteTransaction(function, callback);
    }

    public String getSignedTransactionForAddHistory(byte[] cmd, byte[] key, byte[] value) {
        final Function function = new Function(
                FUNC_ADDHISTORY, 
                Arrays.<Type>asList(new DynamicBytes(cmd),
                new DynamicBytes(key),
                new DynamicBytes(value)),
                Collections.<TypeReference<?>>emptyList());
        return createSignedTransaction(function);
    }

    public Tuple3<byte[], byte[], byte[]> getAddHistoryInput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getInput().substring(10);
        final Function function = new Function(FUNC_ADDHISTORY, 
                Arrays.<Type>asList(), 
                Arrays.<TypeReference<?>>asList(new TypeReference<DynamicBytes>() {}, new TypeReference<DynamicBytes>() {}, new TypeReference<DynamicBytes>() {}));
        List<Type> results = FunctionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple3<byte[], byte[], byte[]>(

                (byte[]) results.get(0).getValue(), 
                (byte[]) results.get(1).getValue(), 
                (byte[]) results.get(2).getValue()
                );
    }

    public List getHistory(byte[] key) throws ContractException {
        final Function function = new Function(FUNC_GETHISTORY, 
                Arrays.<Type>asList(new DynamicBytes(key)),
                Arrays.<TypeReference<?>>asList(new TypeReference<DynamicArray<DynamicBytes>>() {}));
        List<Type> result = (List<Type>) executeCallWithSingleValueReturn(function, List.class);
        return convertToNative(result);
    }

    public static History load(String contractAddress, Client client, CryptoKeyPair credential) {
        return new History(contractAddress, client, credential);
    }

    public static History deploy(Client client, CryptoKeyPair credential) throws ContractException {
        return deploy(History.class, client, credential, getBinary(client.getCryptoSuite()), "");
    }
}
